#include "shell.h"

#if SHELL_DEBUG > 0
#define  MAX_PARAM         4
#define  BACKSPACE		0x08
#define  ENTER			0x0d

typedef struct {
	u8  paranum;
	u8  cmdlen;
	u8  *cmd;
	u8  *param[MAX_PARAM];
	u8  paramlen[MAX_PARAM];
}SH_CMD;

typedef struct {
	const char  *cmd;
	void (*func)(SH_CMD *para);
}EXECENTRY_ST;

#define  SHELL_BUF_SIZE		(64)
static fifo_t shellFifo;
static u8 shellBuf[SHELL_BUF_SIZE];
static char  shellRdBuf[SHELL_BUF_SIZE];
static u8 shellRdLen=0;

static void shell_all_cmd(SH_CMD *para);

u8 ExecEntry(const char *cmd, const EXECENTRY_ST *funcentry, u8 num, SH_CMD *para)
{
	for (; num > 0; num--, funcentry++) {
		if((strlen(funcentry->cmd)==strlen(cmd))&&	\
		 (memcmp(cmd, funcentry->cmd, strlen( funcentry->cmd)) ==0)) {
			if (funcentry->func != NULL) {
				shell_debug("[SHELL] run ->: ");
				shell_debug(funcentry->cmd);
				shell_debug("\n");
				funcentry->func(para);
				return 0;
			}
		}
	}

	return 1;
}

/**
 * @brief int
 * @details asa
 * 
 * @param data ina
 * @param a asa
 */
void shell_buf_push(u8 data)
{
	fifo_put8(&shellFifo, data);
}

static void shell_magc_cmd(SH_CMD *para)
{
	mcr_enable();
}

static void shell_icc_cmd(SH_CMD *para)
{
	s32 sts;

	mml_sc_get_status(&sts);
	mml_sc_intr_unmask_presence_card(); // enable intr

	if (!(sts & MML_SCSTATUS_CARD_NOT_INSERTED)) {
		shell_debug("[DRV] %s, %d::: icc  inserted \n", __func__, __LINE__);
	}
	else{
		shell_debug("[DRV] %s, %d::: icc not  inserted \n", __func__, __LINE__);
	}
}

static void shell_sys_reset(SH_CMD *para)
{
	mml_reset_system();
}

static void shell_random_test(SH_CMD *para)
{

#if 1
	u8	l_tucAESKeys[K_COBRA_USECASE_TRNG_AES_KEY_SIZE];
	trng_gen_aes_key(l_tucAESKeys, K_COBRA_USECASE_TRNG_AES_KEY_SIZE);

	u8 nr, cnt;
	u8 buf[5][K_COBRA_USECASE_TRNG_AES_KEY_SIZE];
	
	for(nr=0; nr <3; nr++ ){
		u8 *l_pucKey = &buf[nr][0];
		trng_read((unsigned int*)l_pucKey, ( K_COBRA_USECASE_TRNG_AES_KEY_SIZE / sizeof(unsigned int) ));
		shell_debug("AES KEY %d: ",nr);
		for( cnt = 0;cnt < K_COBRA_USECASE_TRNG_AES_KEY_SIZE;cnt++ )
		{
			shell_debug("%02X",l_pucKey[cnt]);
		}
		shell_debug("\n");
	}


	volatile u32	*reg_nvsram = (volatile u32*)20080000;

	for(u8 xx=0; xx<1; xx++){
		u32 yy = *reg_nvsram;
		shell_debug("YY=%x\n", yy);
	}

	
	
#else
	u8	l_tucAESKeys[3][K_COBRA_USECASE_TRNG_AES_KEY_SIZE];
	u8 nr, cnt;

	for(nr=0; nr <3; nr++ ){
		u8 *l_pucKey = &l_tucAESKeys[nr][0];
		trng_gen_aes_key(l_pucKey, K_COBRA_USECASE_TRNG_AES_KEY_SIZE);
	}

	for(nr=0; nr <3; nr++ ){
		u8 *l_pucKey = &l_tucAESKeys[nr][0];
		lite_printf("AES KEY %d: ",nr);
		for( cnt = 0;cnt < K_COBRA_USECASE_TRNG_AES_KEY_SIZE;cnt++ )
		{
			shell_debug("%02X",l_pucKey[cnt]);
		}
		lite_printf("\n");
	}
#endif	
}

static void shell_rtc_test(SH_CMD *para)
{ 
	time_t sec;
  	
	sec = rtc_get_seconds();
	shell_debug("[SHELL]RTC now %u seconds => UTC: %s\n", sec, ctime(&sec));
}

static void shell_rtc_set(SH_CMD *para)
{
	time_t sec;

	sec = 1420070400; 
	
	rtc_init(sec, TRUE);
}

static TIMER *shellTmr = NULL;
static u8 shellTmrTest = 0;
static void shell_timer_func(void)
{
	shell_debug("[SHELL] %s, %d \n", __func__, __LINE__);
	shellTmrTest++;
	if(shellTmrTest==10){
		timer_stop(shellTmr);
		shell_debug("[SHELL] %s, %d::: timer stop... \n", __func__, __LINE__);
	}
	shell_rtc_test(NULL);
}

static void shell_timer_test(SH_CMD *para)
{
	shell_debug("[SHELL] %s, %d::: init...\n", __func__, __LINE__);

	shellTmrTest = 0;
	shellTmr = timer_create(shell_timer_func);
	timer_start(shellTmr, 3);
	shell_rtc_test(NULL);
}

static void shell_sys_para_reset(SH_CMD *para)
{
	sys_default_set();
}

static void shell_sys_para_dis(SH_CMD *para)
{
	SYSP_ST *spara;
	
	spara = sys_para_get();

	shell_debug("[SHELL] chksum = %x\n ", spara->chksum);
	shell_debug("[SHELL] refresh = %x\n ", spara->refresh);
	shell_debug("[SHELL] ver = %s\n ", spara->ver);
	shell_debug("[SHELL] test_val = %d\n ", spara->test_val);
}

static void shell_sys_para_set(SH_CMD *para)
{
	SYSP_ST *spara;
	
	spara = sys_para_get();
	spara->test_val = 0x832b;
	
	//sys_para_set();
}

static void shell_sys_para_set2(SH_CMD *para)
{
	SYSP_ST *spara;
	
	spara = sys_para_get();
	spara->test_val = 0x999b;
	
	//sys_para_set();
}

static void shell_ucl_get_version(SH_CMD *para)
{
	shell_debug("[SHELL] ucl-version: %s\n", ucl_get_version());
}

static void shell_ucl_des(SH_CMD *para)
{
	u8 _des_plt_[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
	u8 _des_key_[8] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 };
	u8 _des_res_[8] = {0x76, 0x0e, 0xec, 0xc7, 0x31, 0x46, 0xaf, 0x6c };
	u8 cipherText[8];
	u8 decryptedText[8];


	ucl_des(cipherText, (u8 *)_des_plt_, (u8 *)_des_key_, UCL_CIPHER_ENCRYPT);
	if(memcmp(cipherText, _des_res_, 8) != 0 ){
		shell_debug("[SHELL] ucl_des ENCRYPT error!\n");
	}

	ucl_des(decryptedText, (u8 *)_des_res_, (u8 *)_des_key_, UCL_CIPHER_DECRYPT);
	if(memcmp(decryptedText, _des_plt_, 8) != 0 ){
		shell_debug("[SHELL] ucl_des DECRYPT error!\n");
	}

	shell_debug("[SHELL] ucl_des ENCRYPT/DECRYPT finish!\n");
}

static void shell_ucl_3des(SH_CMD *para)
{
	u8 _tdes_key_[] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
 					    0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10,
 					    0x89,0xAB,0xCD,0xEF,0x01,0x23,0x45,0x67 };
	u8 _tdes_plt_[] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xE7 };
	u8 _tdes_res_[] = {0xDE,0x0B,0x7C,0x06,0xAE,0x5E,0x0E,0xD5 };
	u8 cipherText[8];
	u8 decryptedText[8];
	int err;

	err=ucl_3des(cipherText, (u8 *)_tdes_plt_, (u8 *)_tdes_key_, UCL_CIPHER_ENCRYPT);
	if(UCL_OK!=err){
		shell_debug("[SHELL] ucl_3des ENCRYPT ERROR =%d\n", err);
	}
	if(memcmp(cipherText, _tdes_res_, 8) != 0 ){
		shell_debug("[SHELL] ucl_3des ENCRYPT ERROR \n");
	}

	err=ucl_3des(decryptedText, (u8 *)_tdes_res_, (u8 *)_tdes_key_, UCL_CIPHER_DECRYPT);
	if(UCL_OK!=err){
		shell_debug("[SHELL] ucl_3des DECRYPT ERROR =%d\n", err);
	}
	if(memcmp(decryptedText, _tdes_plt_, 8) != 0 ){
		shell_debug("[SHELL] ucl_3des DECRYPT ERROR \n");
	}

	shell_debug("[SHELL] ucl_3des ENCRYPT/DECRYPT finish... \n");
}

static void shell_enter_upgrade(SH_CMD *para)
{
	iap_enter_upgrade();	
}

static void shell_nvs_read(SH_CMD *para)
{
	u32 mag;
	u32 msg[12];
	
	nvs_read(NVS_ID_MAGIC, (u32 *)&mag, 1);
	shell_debug("[SHELL] nvsram read1: %x\n", mag);

	nvs_read(NVS_ID_DES,  msg, 3);
	shell_debug("[SHELL] nvsram read2: %x\t, %x\t, %x\n", msg[0], msg[1], msg[2]);
	
	nvs_read(NVS_ID_DES,  msg, 5);
	shell_debug("[SHELL] nvsram read3: %x\t, %x\t, %x\t, %x\t, %x\n", 
					msg[0], msg[1], msg[2], msg[3], msg[4]);
}

static void shell_nvs_write(SH_CMD *para)
{
	u32 mag = 0x1234568a;
	u32 msg[] = {0x987654, 0xabcdef12, 0x32ac};
	
	nvs_write(NVS_ID_MAGIC, (u32 *)&mag, 1);
	nvs_write(NVS_ID_DES, 	msg, 	3);
}

static void shell_sys_start_reason(SH_CMD *para)
{
	SYSP_ST *sysp;	

	sysp = sys_para_get();

	if(sysp->startup){
		shell_debug("[SHELL] RTC  Warm Start Up\n");
	}else{
		shell_debug("[SHELL] RTC  Warm Cold Up\n");
	}
}

static void shell_sys_run_mode(SH_CMD *para)
{
	SYSP_ST *sysp;	

	sysp = sys_para_get();

	if(sysp->sysrunmode == SYS_ERR_AES){
		shell_debug("[SHELL] System running in NO_AES mode\n");
	}else if(sysp->sysrunmode == SYS_ERR_KEY){
		shell_debug("[SHELL] System running in NO_KEY mode\n");
	}else{
		shell_debug("[SHELL] System running in USER mode\n");
	}
}

static void shell_create_aes_key(SH_CMD *para)
{
	u8 ret;
	
	trng_check_aes_valid();
	shell_debug("[SHELL] ----------------\n");
	ret= trng_aes_keygen();
	shell_debug("[SHELL] shell_create_aes_key, ret=%d\n", ret);
	shell_nvs_read(NULL);
}

static void shell_dis_monitor_regs(SH_CMD *para)
{
	u32 value;
	
	IO_READ_U32(SECMON_DLRTC,value);
	shell_debug("DRS = 0x%08X\n", value);
	
	IO_READ_U32(SECMON_EXTSC, value);
	shell_debug("External sensors registers: 0x%08X\n", value);
	
	IO_READ_U32(SECMON_INTSC, value);
	shell_debug("Internal sensors registers: 0x%08X\n", value);
	
	IO_READ_U32(SECMON_SECALM, value);
	shell_debug("Security alarm registers: 0x%08X\n", value);
	
	IO_READ_U32(SECMON_SECDIAG, value);
	shell_debug("Security diagnostic registers: 0x%08X\n", value);

}

// for test Queue
static u8 shellQueCmd = 0x00;
LinkQueue shellque2;
static void shell_queue_push(SH_CMD *para)
{
	SHELL_CELL *cell;
	u8 *ch = "1234567890abcdef";
	u16 item;
	
	queue_init(&shellque2);
	shellQueCmd = 3;

	for(int nr=0; nr<3; nr++){
		 cell = (SHELL_CELL *)pvPortMalloc(sizeof(SHELL_CELL));
		 if(cell!=NULL){
		 	memset(cell, '\0', sizeof(SHELL_CELL));
			cell->index= 0;
			cell->val = 0;
		 }else{
		 	shell_debug("[SHELL] shell queue malloc cell err...\n");
			return ;
		 }

		cell->index = shellQueCmd++;
		cell->val = cell->index + 2;
		cell->len = (u16)strlen((const char  *)ch);
		mem_cpy(cell->ptr, ch, cell->len);

		shell_debug("[SHELL] cell addr: %x\n", cell);
		shell_debug("[SHELL] index: %x\n", cell->index);
		shell_debug("[SHELL] val: %x\n", cell->val);

		queue_add(&shellque2, (QElemType )cell);
	}

	item = queue_item(&shellque2);
	shell_debug("\n[SHELL] push queue now item = %d \n", item);
}

static void shell_queue_pop(SH_CMD *para)
{
	SHELL_CELL *cell;
	u16 item;

	item = queue_item(&shellque2);
	shell_debug("\n[SHELL] push queue now item = %d \n", item);

#if  1	
	for(int nr=0; nr<item; nr++){

		cell = (SHELL_CELL *)queue_get(&shellque2);
		shell_debug("[SHELL] cell data out: %x\n", cell);
		
		//item = queue_item(&shellQue);
		//shell_debug("\n[SHELL] push queue now item = %d \n", item);
		shell_debug("[SHELL] pop cell info: \n");
		shell_debug("[SHELL] index = %d\n", cell->index);
		shell_debug("[SHELL] val = %d\n", cell->val);
		shell_debug("[SHELL] len = %d\n", cell->len);
		shell_debug("[SHELL] ptr = %s\n", cell->ptr);

		#if  0
		for(int xx=0; xx<cell->len; xx++){
			shell_debug("%x  ", cell->ptr[xx]);
		}
		shell_debug("\n");
		#endif

		queue_del(&shellque2);       
		vPortFree(cell);
		
	}
#else
	cell = (SHELL_CELL *)queue_get(&shellque2);
	while(cell != NULL){
		shell_debug("[SHELL] cell data out: %x\n", cell);
		
		shell_debug("[SHELL] pop cell info: \n");
		shell_debug("[SHELL] index = %d\n", cell->index);
		shell_debug("[SHELL] val = %d\n", cell->val);
		shell_debug("[SHELL] len = %d\n", cell->len);
		shell_debug("[SHELL] ptr = %s\n", cell->ptr);

		#if  0
		for(int xx=0; xx<cell->len; xx++){
			shell_debug("%x  ", cell->ptr[xx]);
		}
		shell_debug("\n");
		#endif

		queue_del(&shellque2);       
		vPortFree(cell);
		cell = (SHELL_CELL *)queue_get(&shellque2);
	}
#endif
}

static const EXECENTRY_ST  shellMap[] = {
	{"dir",			shell_all_cmd},
	{"magc",			shell_magc_cmd},
	{"icc",			shell_icc_cmd},
	{"tmr",			shell_timer_test},
	{"sysreset",		shell_sys_reset},
	{"random",		shell_random_test},
	{"rtc",			shell_rtc_test},
	{"rtcset",			shell_rtc_set},

	{"nvswr",			shell_nvs_write},
	{"nvsrd",			shell_nvs_read},
	{"nvaes",			shell_create_aes_key},

	{"parawr",		shell_sys_para_reset},
	{"parard",		shell_sys_para_dis},
	{"paraset",		shell_sys_para_set},
	{"paraset2",		shell_sys_para_set2},

	{"uclver",			shell_ucl_get_version},
	{"des",			shell_ucl_des},
	{"3des",			shell_ucl_3des},

	{"upgrade",		shell_enter_upgrade},
	{"rtcstart",		shell_sys_start_reason},
	{"sysmode",		shell_sys_run_mode},

	{"monreg",		shell_dis_monitor_regs},

	{"quepush",		shell_queue_push},
	{"quepop",		shell_queue_pop},
	
	//{"spi",		nfc_spi_trans_test},	
};

static void shell_all_cmd(SH_CMD *para)
{
	u8 nr;
	
	for(nr=1; nr<sizeof(shellMap)/sizeof(shellMap[0]); nr++){
		if (shellMap[nr].func != NULL){
			shell_debug("[SHELL]\t%s\n", shellMap[nr].cmd);
		}
	}
}

static void shell_func_task( void *pvParameters )
{
	u8 nr;
	
	while(1){
		if(!fifo_empty(&shellFifo)){
			fifo_get8(&shellFifo, (u8 *)&shellRdBuf[shellRdLen++]);

			if(BACKSPACE==shellRdBuf[shellRdLen-1]){
				shellRdLen--;
				if(shellRdLen>0){
					shellRdLen--;
				}
			}

			shell_debug("[SHELL] input: ");
			for(nr=0; nr<(shellRdLen); nr++){
				shell_debug("%c", shellRdBuf[nr]);
			}
			shell_debug("\n");

			if(ENTER==shellRdBuf[shellRdLen-1]){
				shellRdBuf[shellRdLen-1] = '\0';
				ExecEntry(shellRdBuf, shellMap, sizeof(shellMap)/sizeof(shellMap[0]), NULL);

				shellRdLen = 0;
				memset(shellRdBuf, '\0', SHELL_BUF_SIZE);
			}
			else{
				if(shellRdLen>SHELL_BUF_SIZE){
					shellRdLen--;
				}
			}
		}
	}
}


void shell_init(void)
{
	s32 err;

	shellRdLen = 0;
	memset(shellRdBuf, '\0', SHELL_BUF_SIZE);
	memset(shellBuf, '\0', SHELL_BUF_SIZE);
	fifo_init(&shellFifo, shellBuf, SHELL_BUF_SIZE);
	
	err=xTaskCreate( shell_func_task, "shell_func_task", 500, NULL, FixedPriority, NULL );
	if(err!=pdPASS) while(1);
}

#else
void shell_init(void){}
void shell_buf_push(u8 data){}

#endif	 
